﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using Amazon.Runtime;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using ICNETServices;
using ICNETDAL;

// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace StaleCacheDeletionService
{


    partial class StaleDeletionService : ServiceBase
    {

        /// <summary>
        /// Log4net logging object
        /// </summary>
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Timer used to schedule the deletion polling 
        /// </summary>
        private Timer deletionTimer;

        /// <summary>
        /// Amazon DynamoDB configuration object
        /// </summary>
        private AmazonDynamoDBConfig amazonDynamoConfig;

        /// <summary>
        /// Amazon DynamoDB client
        /// </summary>
        private AmazonDynamoDBClient amazonDynamoClient;


        private Dictionary<string, AttributeValue> staleScanExpressionValues;
        private string staleScanExpression;

        public StaleDeletionService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            string currentUTCTime = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            Log.Info("=================== SERVICE STARTED @ " + currentUTCTime + " ===================");
            Log.Info("=================== ON START ====================");
            this.amazonDynamoConfig = new AmazonDynamoDBConfig();
            this.amazonDynamoConfig.ServiceURL = AWSConstants.DynamoServiceURL;
            //Log.Info(">>> Getting Credentials");
            //AWSCredentials credentials = new StoredProfileAWSCredentials("default");
            //Log.Info(">>> Got Credentials: " + credentials.GetCredentials());
            Log.Info(">>> DynamoDB config complete");
            Log.Info(">>> Setting up DynamoDB client");
            this.amazonDynamoClient = new AmazonDynamoDBClient(this.amazonDynamoConfig);
            Log.Info(">>> Client set-up complete");
            Log.Info(">>> Creating service task timer");
            deletionTimer = new Timer(this.TimerTick, null, 0, AWSConstants.DeleteProcessing.PollIntervalInSeconds*1000);
            Log.Info("=================== ON START COMPLETE ====================");
        }

        public void TimerTick(Object obj)
        {
            string currentUTCTime = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            Log.Info("=================== TIMER TICK @ " + currentUTCTime + " ===================");
            Log.Info(">>> Checking for stale messages based off of: " + currentUTCTime);
            ////checking the content cache
            // set up sxpression value

            Log.Info("====== Starting with FeedCache ======");
            staleScanExpressionValues = new Dictionary<string, AttributeValue>()
            {
                { ":currentTime", new AttributeValue(currentUTCTime)}
            };

            staleScanExpression = "#ExpiresTime < :currentTime";

            ScanRequest requestExpiredItems;
            List<WriteRequest> deleteRequestList;
            DeleteRequest deleteRequest;
            BatchWriteItemRequest bulkDelete;
            BatchWriteItemResult result;

            //First remove stale Feeds
            requestExpiredItems = new ScanRequest(AWSConstants.ContentFeedProcessing.DynamoInfo.TableName);
            requestExpiredItems.ExpressionAttributeNames = new Dictionary<string, string>(){
                {"#FeedHash", "_FeedHash"},
                {"#ExpiresTime", "_ExpiresTime"},
                {"#ContentHash", "_ContentHash"}
            };

            requestExpiredItems.ExpressionAttributeValues = staleScanExpressionValues;
            requestExpiredItems.FilterExpression = staleScanExpression;
            requestExpiredItems.ProjectionExpression = "#FeedHash, #ContentHash, #ExpiresTime";

            ScanResult expiredItemsResult = amazonDynamoClient.Scan(requestExpiredItems);
            Log.Info(">>> Found " + expiredItemsResult.Count + " feed items that are expired...");

            if (expiredItemsResult.Count > 0)
            {
                deleteRequestList = new List<WriteRequest>();

                foreach (Dictionary<string, AttributeValue> item in expiredItemsResult.Items)
                {
                    Log.Info(">>>>> Item: " + item["_FeedHash"].S + " / " + item["_ContentHash"].N);
                    deleteRequest = new DeleteRequest(new Dictionary<string, AttributeValue>
                    {
                        {"_FeedHash", new AttributeValue{S = item["_FeedHash"].S}},
                        {"_ContentHash", new AttributeValue{N = item["_ContentHash"].N}}
                    }
                    );
                    deleteRequestList.Add(new WriteRequest(deleteRequest));

                }

                doBatchDelete(deleteRequestList, AWSConstants.ContentFeedProcessing.DynamoInfo.TableName);
            }
            
            //Next remove stale content from ContentCache
            Log.Info("====== Checking ContentCache ======");
            requestExpiredItems = new ScanRequest(AWSConstants.ContentProcessing.DynamoInfo.TableName);
            requestExpiredItems.ExpressionAttributeNames = new Dictionary<string, string>(){
                {"#ContentHash", "_ContentHash"},
                {"#DistID","distributionID"},
                {"#ExpiresTime", "_ExpiresTime"}                
            };

            requestExpiredItems.ExpressionAttributeValues = staleScanExpressionValues;
            requestExpiredItems.FilterExpression = staleScanExpression;
            requestExpiredItems.ProjectionExpression = "#ContentHash, #DistID, #ExpiresTime";

            expiredItemsResult = amazonDynamoClient.Scan(requestExpiredItems);
            Log.Info(">>> Found " + expiredItemsResult.Count + " content items that are expired...");

            if (expiredItemsResult.Count > 0)
            {
                deleteRequestList = new List<WriteRequest>();

                foreach (Dictionary<string, AttributeValue> item in expiredItemsResult.Items)
                {
                    Log.Info(">>>>> Item: " + item["distributionID"].S + " / " + item["_ContentHash"].N);
                    deleteRequest = new DeleteRequest(new Dictionary<string, AttributeValue>
                    {                       
                        {"_ContentHash", new AttributeValue{N = item["_ContentHash"].N}}
                    }
                    );
                    deleteRequestList.Add(new WriteRequest(deleteRequest));

                }

                doBatchDelete(deleteRequestList, AWSConstants.ContentProcessing.DynamoInfo.TableName);

            }
            //Finally remove stale DEs from EDXLCache  
            Log.Info("====== Checking EDXLCache ======");
            requestExpiredItems = new ScanRequest(AWSConstants.DEProcessing.DynamoInfo.TableName);
            requestExpiredItems.ExpressionAttributeNames = new Dictionary<string, string>(){
                {"#distID", "distributionID"},
                {"#ExpiresTime", "_ExpiresTime"},
                {"#senderID", "senderID"}
            };

            requestExpiredItems.ExpressionAttributeValues = staleScanExpressionValues;
            requestExpiredItems.FilterExpression = staleScanExpression;
            requestExpiredItems.ProjectionExpression = "#distID, #senderID, #ExpiresTime";
            

            expiredItemsResult = amazonDynamoClient.Scan(requestExpiredItems);
            Log.Info(">>> Found " + expiredItemsResult.Count + " DE items that are expired...");

            int itemNum = 1;
            if (expiredItemsResult.Count > 0)
            {
                deleteRequestList = new List<WriteRequest>();

                
                foreach (Dictionary<string, AttributeValue> item in expiredItemsResult.Items)
                {
                    Log.Info(">>>>> Item: " + item["senderID"].S + " / " + item["distributionID"].S);
                    deleteRequest = new DeleteRequest(new Dictionary<string, AttributeValue>
                        {
                            {"senderID", new AttributeValue{S = item["senderID"].S}},
                            {"distributionID", new AttributeValue{S = item["distributionID"].S}}
                        }
                    );

                    deleteRequestList.Add(new WriteRequest(deleteRequest));                                     

                }

                doBatchDelete(deleteRequestList, AWSConstants.DEProcessing.DynamoInfo.TableName);



                //requestExpiredItems = new ScanRequest(AWSConstants.ContentProcessing.DynamoInfo.TableName);
                //requestExpiredItems.ExpressionAttributeNames = new Dictionary<string, string>(){
                //    {"#ContentHash", "_ContentHash"},
                //    {"#ExpiresTime", "_ExpiresTime"}
                //};
                //requestExpiredItems.ExpressionAttributeValues = staleScanExpressionValues;
                //requestExpiredItems.FilterExpression = staleScanExpression;
                //requestExpiredItems.ProjectionExpression = "#ContentHash, #ExpiresTime";

                //expiredItemsResult = amazonDynamoClient.Scan(requestExpiredItems);
                //Log.Info(">>> Found " + expiredItemsResult.Count + " that are expired...");

                //BatchWriteItemRequest bulkDelete = new BatchWriteItemRequest();
                //List<WriteRequest> deleteRequestList = new List<WriteRequest>();
                //DeleteItemRequest deleteRequest;
                //foreach (Dictionary<string, AttributeValue> item in expiredItemsResult.Items)
                //{
                //    Log.Info(">>>>> Item: " + item["_FeedHash"].S + " / " + item["_ContentHash"].N);  
                //    deleteRequest = new DeleteItemRequest("Fee")
                //}
            }
            currentUTCTime = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            Log.Info("=================== WORK COMPLETE @ " + currentUTCTime + " ===================");
        }
        protected override void OnStop()
        {
            string currentUTCTime = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
            Log.Info("=================== SERVICE STOPPED @ " + currentUTCTime + " ===================");
        }

        private void doBatchDelete(List<WriteRequest> deleteRequestList, string tableName)
        {
           
            BatchWriteItemResult result;
            List<WriteRequest> deleteForBatch = new List<WriteRequest>();
            for (int i = 0; i < deleteRequestList.Count; i++)
            {

                //Log.Info("Working on message " + (i+1));
                deleteForBatch.Add(deleteRequestList[i]);
               // Log.Info("Batch Delete List is now " + deleteForBatch.Count + " items long...");
                if (deleteForBatch.Count == 25 || i == (deleteRequestList.Count-1))
                {
                    //Log.Info("We're at 25 or end of list. Need to send batch!");
                    //send batch request

                    BatchWriteItemRequest bulkDelete = new BatchWriteItemRequest

                    {
                        RequestItems = new Dictionary<string, List<WriteRequest>>
                {
                    {tableName,deleteForBatch}
                }
                    };


                    do
                    {
                        Log.Info(">>>>> Doing Bulk Delete of " + bulkDelete.RequestItems[tableName].Count + " items.");

                        // Issue request and retrieve items
                        result = amazonDynamoClient.BatchWriteItem(bulkDelete);

                        // Some items may not have been processed!
                        //  Set RequestItems to the result's UnprocessedItems and reissue request
                        bulkDelete.RequestItems = result.UnprocessedItems;
                        Log.Info(result.UnprocessedItems.Count + " items were not processed...");
                    } while (result.UnprocessedItems.Count > 0);


                    //reset list
                    deleteForBatch = new List<WriteRequest>();

                }





            }
            
            
            
        }
    }
}
